package cnam.smb215.findfriends;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONObject;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.OverlayItem;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.Toast;

@SuppressLint("NewApi")
public class MainActivity extends MapActivity {
	String TAG = "findFriends";
	int ImageViewRefreshID = 10;
	int ImageViewUpdateLocationID = 11;
	int ImageViewSearchID = 12;
	
	//Views and Layouts
	RelativeLayout mRelativeLayoutMainRoot;
	MapView mMapView;
	ImageView mImageViewRefresh, mImageViewUpdateLocation, mImageViewSearch;
	MyProgressDialog mProgressDialog;	
	
	//Async Taks
	UpdateLocationAyncTask mUpdateLocationAyncTask;
	LoadUsersAsyncTask mLoadUsersAsyncTask;
	
	//Location
	LocationManager mLocationManager;
	LocationListener mLocationListener;
	
	//Flags
	boolean isFirstBoot = true;
	boolean isUpdateLocation = true;
	boolean isUpdateLocationAsyncTaskRunning = false;
	boolean isAutoNavigateToCurrentLocation = true;
	boolean isUserAdded = false;
	boolean isZoomToDefault = true;
	
	//Map
	List<Overlay> mMapOverlays;
	//Current user
	Person mUserPerson;
	PersonItemizedOverlay mUserItemizedOverlay;
	
	//Other users
	List<Person> mListUsers;
	List<PersonItemizedOverlay> mListItemizedUsers;
	
	int orientation;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		mRelativeLayoutMainRoot = (RelativeLayout)findViewById(R.id.relativeLayoutMainRoot);
		
		mImageViewRefresh = new ImageView(this);
		mImageViewRefresh.setOnTouchListener(mImageViewsTouchListener);
		mImageViewRefresh.setId(ImageViewRefreshID);
		mImageViewRefresh.setBackgroundColor(getResources().getColor(R.color.grey));
		mImageViewRefresh.setImageDrawable(getResources().getDrawable(R.drawable.refresh));
		RelativeLayout.LayoutParams paramsRefresh = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		paramsRefresh.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		paramsRefresh.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
		paramsRefresh.bottomMargin = 20;
		paramsRefresh.rightMargin = 20;
		mImageViewRefresh.setLayoutParams(paramsRefresh);
		
		mImageViewUpdateLocation = new ImageView(this);
		mImageViewUpdateLocation.setOnTouchListener(mImageViewsTouchListener);
		mImageViewUpdateLocation.setId(ImageViewUpdateLocationID);
		mImageViewUpdateLocation.setBackgroundColor(getResources().getColor(R.color.grey));
		mImageViewUpdateLocation.setImageDrawable(getResources().getDrawable(R.drawable.bulbgrey));
		RelativeLayout.LayoutParams paramsUpdateLoc = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		paramsUpdateLoc.addRule(RelativeLayout.ABOVE, mImageViewRefresh.getId());
		paramsUpdateLoc.addRule(RelativeLayout.ALIGN_RIGHT, mImageViewRefresh.getId());
		paramsUpdateLoc.bottomMargin = 15;
		mImageViewUpdateLocation.setLayoutParams(paramsUpdateLoc);
		
		mImageViewSearch = new ImageView(this);
		mImageViewSearch.setOnTouchListener(mImageViewsTouchListener);
		mImageViewSearch.setId(ImageViewSearchID);
		mImageViewSearch.setBackgroundColor(getResources().getColor(R.color.grey));
		mImageViewSearch.setImageDrawable(getResources().getDrawable(R.drawable.search));
		RelativeLayout.LayoutParams paramsSearch = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		paramsSearch.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		paramsSearch.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
		paramsSearch.bottomMargin = 60;
		paramsSearch.leftMargin = 20;
		mImageViewSearch.setLayoutParams(paramsSearch);

		
		mRelativeLayoutMainRoot.addView(mImageViewRefresh);
		mRelativeLayoutMainRoot.addView(mImageViewUpdateLocation);
		mRelativeLayoutMainRoot.addView(mImageViewSearch);

		mProgressDialog = new MyProgressDialog(this, this);
		
		orientation = getResources().getConfiguration().orientation;
		
		//Globals initialization
		if(Globals.DEFAULT_ICON == null) {
			Globals.DEFAULT_ICON = this.getResources().getDrawable(R.drawable.pin_green);
		}
		if(Globals.DEFAULT_ICON_USERS == null) {
			Globals.DEFAULT_ICON_USERS = this.getResources().getDrawable(R.drawable.pin_red);
		}
		
		//Reading Preferences
		SharedPreferences sharedPreferences = getSharedPreferences(Globals.FILE_NAME_PREF, MODE_PRIVATE);
		

		int id = sharedPreferences.getInt(Globals.PREF_ID, 0);
		String name = sharedPreferences.getString(Globals.PREF_NAME, "Android User");
		String email = sharedPreferences.getString(Globals.PREF_EMAIL, "android@gmail.com");
		Globals.MY_ID = id;
		Globals.MY_EMAIL = email;
				
		mUserPerson = new Person(id, name, email);
		mUserItemizedOverlay = new PersonItemizedOverlay(mUserPerson, this);
		
		mListUsers = new ArrayList<Person>();
		mListItemizedUsers = new ArrayList<PersonItemizedOverlay>();
		
		mMapView = (MapView)findViewById(R.id.mapview);	
		mMapView.setBuiltInZoomControls(true);
		mMapOverlays = mMapView.getOverlays();

		mLocationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE);
		mLocationListener = new LocationListener() {
			public void onStatusChanged(String provider, int status, Bundle extras) {}
			
			public void onProviderEnabled(String provider) {}
			
			public void onProviderDisabled(String provider) {}
			
			public void onLocationChanged(Location location) {
				GeoPoint point = new GeoPoint((int)(location.getLatitude() * 1E6), (int)(location.getLongitude() * 1E6));
				OverlayItem overlayitem = new OverlayItem(point, null, null);
				
				mUserItemizedOverlay.addOverlay(overlayitem);
				
				if(isAutoNavigateToCurrentLocation) {
					isAutoNavigateToCurrentLocation = false;
					mMapView.getController().animateTo(point);
				}
				if(!isUserAdded) {
					isUserAdded = true;
					mMapOverlays.add(mUserItemizedOverlay);
				}
				if(isZoomToDefault) {
					isZoomToDefault = false;
					mMapView.getController().setZoom(Globals.DEFAULT_ZOOM_LEVEL);
				}
				if(isUpdateLocation) {
					Log.e(TAG, "loc updated");
					isUpdateLocation = false;
					isUpdateLocationAsyncTaskRunning = true;
					mUpdateLocationAyncTask = new UpdateLocationAyncTask();
					mUpdateLocationAyncTask.execute(point.getLatitudeE6(), point.getLongitudeE6());
					mProgressDialog.setMessage("Updating location on server");
				}
				if(isFirstBoot) {
					isFirstBoot = false;
					Log.e(TAG, "updating users");
					updateUsers();
				}
			}
		};
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		mLocationManager.removeUpdates(mLocationListener);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		mLocationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 0, 0, mLocationListener);		
	}
	
	@Override
	public void onConfigurationChanged(Configuration newConfig) {
		super.onConfigurationChanged(newConfig);
		
		if(newConfig.orientation != orientation) {
		}
		orientation = newConfig.orientation;
	}
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		//getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
	
	@Override
	public void onBackPressed() {		
		if(isUpdateLocationAsyncTaskRunning) {
			Log.e(TAG, "Calling async task cancel");
			mUpdateLocationAyncTask.cancel(true);
		}
		else if(isUpdateLocation) {
			isUpdateLocation = false;
		}
		else {
			super.onBackPressed();
		}
	}

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}
	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if(requestCode == 1) {
			if(resultCode == RESULT_OK) {
				int index = data.getIntExtra(Globals.EXTRA_RESULT, -1);
				if(index >= 0 && index < mListUsers.size()) {
					GeoPoint point = new GeoPoint(mListUsers.get(index).getLatitude(), mListUsers.get(index).getLongitude());
					mMapView.getController().animateTo(point);
				}
			}
		}
	}
	
	/*
	 * Functions
	 */
	private void toastMessage(String message) {
		Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
	}
	
	private Date convertToDate(String dateString) {
		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
		Date convertedDate;
		
		try {
			convertedDate = dateFormat.parse(dateString);
		} catch (ParseException e) {
			e.printStackTrace();
			return null;
		}
		return convertedDate;
	}
	
	private void updateUsers() {
		mMapOverlays.clear();
		mListUsers.clear();
		mListItemizedUsers.clear();
		
		mImageViewRefresh.setEnabled(false);
		mImageViewUpdateLocation.setEnabled(false);

		isUserAdded = false;
		mLocationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, mLocationListener, getMainLooper());
		
		toastMessage("Updating users list.");
		mLoadUsersAsyncTask = new LoadUsersAsyncTask();
		mLoadUsersAsyncTask.execute();
	}

	
	/*
	 * Touch Listener
	 */
	private boolean mIsTouchInsideView;
	private OnTouchListener mImageViewsTouchListener = new OnTouchListener() {
		public boolean onTouch(View v, MotionEvent event) {
			switch(event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				mIsTouchInsideView = true;
				v.setBackgroundColor(getResources().getColor(R.color.yellow_selected));
				break;
				
			case MotionEvent.ACTION_MOVE:
				int x = (int)event.getX();
				int y = (int)event.getY();

				if(x < 0 || y < 0 || x >= v.getWidth() || y >= v.getHeight()){
					mIsTouchInsideView = false;
					v.setBackgroundColor(getResources().getColor(R.color.grey));
		        }
				break;
				
			case MotionEvent.ACTION_UP:
				if(mIsTouchInsideView) {
					v.setBackgroundColor(getResources().getColor(R.color.grey));

					if(v.getId() == ImageViewRefreshID) {
						updateUsers();
					}
					else if(v.getId() == ImageViewUpdateLocationID) {
						Log.e(TAG, "called update loc");
						mProgressDialog.setMessage("Getting position from GPS");
						mProgressDialog.setIndeterminate(true);
						mProgressDialog.show();
						isAutoNavigateToCurrentLocation = true;
						isUpdateLocation = true;
						mLocationManager.requestSingleUpdate(LocationManager.NETWORK_PROVIDER, mLocationListener, getMainLooper());
					}
					else if(v.getId() == ImageViewSearchID) {
						ArrayList<String> listNames = new ArrayList<String>();
						for(Person person:mListUsers) {
							listNames.add(person.getName());
						}
						
						Intent intent = new Intent(MainActivity.this, SearchActivity.class);
						intent.putExtra(Globals.EXTRA_NAMES, listNames);
						startActivityForResult(intent, 1);
					}
				}
				break;
			}
			return true;
		}
	};
	
	private class LoadUsersAsyncTask extends AsyncTask<Void, Void, Person[]> {
		@Override
		protected Person[] doInBackground(Void... params) {
			String response = "";
			String url = Globals.SERVER_URL;

			DefaultHttpClient client = new DefaultHttpClient();			
			HttpPost httpPost = new HttpPost(url);

			try {
				List<NameValuePair> getParams = new LinkedList<NameValuePair>();
				getParams.add(new BasicNameValuePair(Globals.URL_PARAM_TYPE, String.valueOf(Globals.TYPE_GET_ALL_PEOPLE)));
				httpPost.setEntity(new UrlEncodedFormEntity(getParams));

				HttpResponse execute = client.execute(httpPost);
				InputStream content = execute.getEntity().getContent();

				BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
				String s = "";
				while ((s = buffer.readLine()) != null) {
					response += s;
				}
				
				JSONArray jsonArray = new JSONArray(response);
				Person[] persons = new Person[jsonArray.length()];
				
				for(int i=0;i<jsonArray.length();i++) {
					JSONObject jsonObject = jsonArray.getJSONObject(i);
					int id = jsonObject.getInt("ID");
					String name = jsonObject.getString("name");
					String email = jsonObject.getString("email");
					int latitude = jsonObject.getInt("latitude");
					int longitude = jsonObject.getInt("longitude");
					Date lastSeen = convertToDate(jsonObject.getString("lastseen"));

					persons[i] = new Person(id, name, email, latitude, longitude, lastSeen);
				}
				return persons;
				
			} catch (Exception e) {
				Log.e("findFriends", "Error with server: " + e.getMessage());
				return null;
			}
		}
		
		@Override
		protected void onPostExecute(Person[] result) {
			if(result == null) {
				toastMessage("Updating users failed!");
			}
			else {
				Log.e(TAG, "total users " + result.length);
				
				for(int i=0;i<result.length;i++) {
					if(result[i].getID() == Globals.MY_ID) {
						continue;
					}
					mListUsers.add(result[i]);
				}
				Collections.sort(mListUsers);
				
				for(int i=0;i<mListUsers.size();i++) {
					Person user = mListUsers.get(i);
					
					PersonItemizedOverlay personItemizedOverlay = new PersonItemizedOverlay(user, MainActivity.this);
					GeoPoint point = new GeoPoint(user.getLatitude(), user.getLongitude());
					OverlayItem overlayitem = new OverlayItem(point, null, null);
					
					mListItemizedUsers.add(personItemizedOverlay);

					personItemizedOverlay.addOverlay(overlayitem);
					mMapOverlays.add(personItemizedOverlay);
				}
				toastMessage("Users updated!");
			}
			
			mImageViewRefresh.setEnabled(true);
			mImageViewUpdateLocation.setEnabled(true);
		}
	}
	
	private class UpdateLocationAyncTask extends AsyncTask<Integer, Void, Integer> {
		@Override
		protected Integer doInBackground(Integer... params) {
			int latitude = params[0];
			int longitude = params[1];
			String response = "";
			String url = Globals.SERVER_URL;

			DefaultHttpClient client = new DefaultHttpClient();			
			HttpPost httpPost = new HttpPost(url);

			try {
				List<NameValuePair> getParams = new LinkedList<NameValuePair>();
				getParams.add(new BasicNameValuePair(Globals.URL_PARAM_TYPE, String.valueOf(Globals.TYPE_UPDATE_LOCATION)));
				getParams.add(new BasicNameValuePair(Globals.URL_PARAM_EMAIL, Globals.MY_EMAIL));
				getParams.add(new BasicNameValuePair(Globals.URL_PARAM_LATITUDE, latitude+""));
				getParams.add(new BasicNameValuePair(Globals.URL_PARAM_LONGITUDE, longitude+""));
				httpPost.setEntity(new UrlEncodedFormEntity(getParams));

				HttpResponse execute = client.execute(httpPost);
				InputStream content = execute.getEntity().getContent();

				BufferedReader buffer = new BufferedReader(new InputStreamReader(content));
				String s = "";
				while ((s = buffer.readLine()) != null) {
					response += s;
				}
				
				int res_id = Integer.parseInt(response);
				return res_id;

			} catch (Exception e) {
				Log.e("findFriends", "Error with server: " + e.getMessage());
				return null;
			}
		}

		@Override
		protected void onPostExecute(Integer result) {
			if(result == null) {
				toastMessage("Error with Server!! Please try again after checking your connection");
			}
			else if(result > 0) {
				toastMessage("Location updated.");
			}
			else if(result == 0) {
				toastMessage("Location coudln't be updated on server.");
			}
			isUpdateLocationAsyncTaskRunning = false;
			mProgressDialog.dismissManually();
		}
		
		@Override
		protected void onCancelled() {
			super.onCancelled();
			isUpdateLocationAsyncTaskRunning = false;
			mProgressDialog.dismissManually();
			toastMessage("Location update canceled.");
		}
	}
}
